package com.lvmama.java.rhino.spark.utils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

import com.lvmama.java.rhino.spark.entity.AccessLog;
import com.lvmama.java.rhino.spark.entity.BaseLog;
import com.lvmama.java.rhino.spark.entity.DeviceInfoLog;
import com.lvmama.java.rhino.spark.entity.DubboLogInfo;
import com.lvmama.java.rhino.spark.entity.LogInfo;
import com.lvmama.java.rhino.spark.entity.UserInfoLog;
import com.lvmama.java.rhino.spark.tables.RequestTimeDetail;

public class LogParseUtils {
	
	public static DubboLogInfo parseDubboLog(String logContent) {
		DubboLogInfo dubboLogInfo = new DubboLogInfo();
		if(!LogProcessorUtil.isDubboMethodEndLogContent(logContent) && !LogProcessorUtil.isDubboMethodStartLogContent(logContent)) {
			return dubboLogInfo;
		}
		logContent = logContent.replaceAll(",", "");
		String[] logs = logContent.split("\\s+");
		if(logs.length < 9) {
			return dubboLogInfo;
		}
		dubboLogInfo.set_interface(logs[3]);
		dubboLogInfo.set_method(logs[6]);
		dubboLogInfo.setFlag(logs[8]);
		
		return dubboLogInfo;
	}
	
	/**
	 * 将一整行日志解析成一个日志对象
	 * @param log
	 * @return
	 */
	public static LogInfo parseLog(String log) {
		String[] logs = log.split("\\s+");
		LogInfo logInfo = new LogInfo();
		if(logs.length < 6) {
			return null;
		}
		String dateStr = logs[0] + " " + logs[1];
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
		try {
			logInfo.setPrintTime(format.parse(dateStr));
		} catch (ParseException e) {
			return null;
		}
		String levelAppName = logs[2];
		levelAppName = levelAppName.replace("[LvLogS]", ",");
		String[] levelAppNames = levelAppName.split(",");
		logInfo.setLogLevel(levelAppNames[0]);
		logInfo.setAppName(levelAppNames[1]);
		String threadName = logs[3];
		int indexOf = threadName.indexOf("]");
		if(indexOf == -1) {
			return null;
		}
		threadName = threadName.substring(1, indexOf);
		logInfo.setThreadName(threadName);
		String classNameInfo = logs[4];
		indexOf = classNameInfo.indexOf(")");
		if(indexOf == -1) {
			return null;
		}
		classNameInfo = classNameInfo.substring(1, indexOf);
		if(!classNameInfo.matches("\\w+.\\w+:\\d+")) {
			return null;
		}
		String[] classNameInfos = classNameInfo.split(":");
		logInfo.setClassName(classNameInfos[0]);
		logInfo.setClassLineNum(classNameInfos[1]);
		String[] logStrs = log.split(logs[4]);
		if(logStrs.length < 2) {
			return null;
		}
		String content = logStrs[1];
		indexOf = content.indexOf("-");
		if(indexOf == -1) {
			return null;
		}
		content = content.substring(indexOf+2);
		logInfo.setContent(content);
		return logInfo;
	}
	
	public static BaseLog parseClientServiceCommonParam(String log) {
		if(StringUtils.isBlank(log)) {
			return null;
		}
		String[] commonParams = log.split(Constants.SEPERATOR);
		if(commonParams.length<20) {
			return null;
		}
		
		BaseLog baseLog = new BaseLog();
		baseLog.logType = commonParams[0];
		baseLog.timeStamp = commonParams[1];
		DeviceInfoLog deviceInfoLog = new DeviceInfoLog();
		deviceInfoLog.firstChannel = commonParams[2];
		deviceInfoLog.secondChannel = commonParams[3];
		deviceInfoLog.udid = commonParams[4];
		deviceInfoLog.osVersion = commonParams[5];
		deviceInfoLog.userAgent = commonParams[6];
		baseLog.deviceInfo = deviceInfoLog;
		UserInfoLog userInfoLog = new UserInfoLog();
		userInfoLog.userId = commonParams[7];
		userInfoLog.ip = commonParams[8];
		userInfoLog.lvversion = commonParams[9];
		userInfoLog.longitude = commonParams[10];
		userInfoLog.latitude = commonParams[11];
		userInfoLog.lvsessionid = commonParams[12];
		userInfoLog.adChannel = commonParams[13];
		baseLog.userInfo = userInfoLog;
		AccessLog accessLog = new AccessLog();
		accessLog.method = commonParams[14];
		accessLog.version = commonParams[15];
		accessLog.pageCode = commonParams[16];
		accessLog.lastPageCode = commonParams[17];
		accessLog.productType = commonParams[18];
		accessLog.clientTimestamp = commonParams[19];
		baseLog.accessLog = accessLog;
		
		return baseLog;
	}
	
	public static List<String> parseClientServiceSpecialParam(String logCotent) {
		if(StringUtils.isBlank(logCotent)) {
			return null;
		}
		String[] commonParams = logCotent.split(Constants.SEPERATOR);
		if(commonParams.length < 1) {
			return null;
		}
		return Arrays.asList(commonParams);
	}
	
	public static List<RequestTimeDetail> parseApiRequestTimeDetail(List<String> logList) {
		List<RequestTimeDetail> apiRequestTimeDetailList = new ArrayList<RequestTimeDetail>();
		if(logList == null || logList.isEmpty()) {
			return apiRequestTimeDetailList;
		}
		Collections.sort(logList, new LogComparator());
		LogInfo startLogInfo = LogParseUtils.parseLog(logList.get(0));
		long startTime = startLogInfo.getPrintTime().getTime();
		LogInfo endLogInfo = LogParseUtils.parseLog(logList.get(logList.size()-1));
		long endTime = endLogInfo.getPrintTime().getTime();
		RequestTimeDetail total = new RequestTimeDetail();
		total.setThreadName(startLogInfo.getThreadName());
		total.setTimeType(LogEnums.REQUEST_TIME_TYPE.ALL.name());
		total.setRequestTime(startTime);
		total.setResponseTime(endTime);
		total.setMillisecond(endTime - startTime);
		// 所有dubbo的性能日志解析结果
		List<LogInfo> logInfoList = new ArrayList<LogInfo>();
		for(String log: logList) {
			LogInfo logInfo = LogParseUtils.parseLog(log);
			if(logInfo == null) {
				continue;
			}
			if(Constants.COMMON_PARAM_DATA.equals(logInfo.getClassName())) {
				String content = logInfo.getContent();
				BaseLog baseLog = LogParseUtils.parseClientServiceCommonParam(content);
				total.setRequestName(baseLog.accessLog.method);
				total.setRequestVersion(baseLog.accessLog.version);
			}
			if(Constants.DUBBO_PARAM_DATA.equals(logInfo.getClassName()) && (LogProcessorUtil.isDubboMethodStartLogContent(logInfo.getContent()) || LogProcessorUtil.isDubboMethodEndLogContent(logInfo.getContent()))) {
				DubboLogInfo dubboLogInfo = parseDubboLog(logInfo.getContent());
				logInfo.setDubboLog(dubboLogInfo);
				logInfoList.add(logInfo);
			}
		}
		apiRequestTimeDetailList.add(total);
		
		RequestTimeDetail tempApiRequestTimeDetail = new RequestTimeDetail();
		for(int i=0; i<logInfoList.size(); i++) {
			LogInfo logInfo = logInfoList.get(i);
			if("start".equals(logInfo.getDubboLog().getFlag())) {
				tempApiRequestTimeDetail.setRequestTime(logInfo.getPrintTime().getTime());
				tempApiRequestTimeDetail.setRequestName(logInfo.getDubboLog().get_interface());
				tempApiRequestTimeDetail.setRequestVersion(logInfo.getDubboLog().get_method());
				tempApiRequestTimeDetail.setThreadName(logInfo.getThreadName());
				tempApiRequestTimeDetail.setTimeType(LogEnums.REQUEST_TIME_TYPE.DUBBO.name());
			}
			if("end".equals(logInfo.getDubboLog().getFlag())) {
				if(StringUtils.isNotBlank(tempApiRequestTimeDetail.getRequestName()) && StringUtils.isNotBlank(tempApiRequestTimeDetail.getRequestVersion())) {
					if(tempApiRequestTimeDetail.getRequestName().equals(logInfo.getDubboLog().get_interface()) && tempApiRequestTimeDetail.getRequestVersion().equals(logInfo.getDubboLog().get_method())) {
						tempApiRequestTimeDetail.setResponseTime(logInfo.getPrintTime().getTime());
						tempApiRequestTimeDetail.setMillisecond(logInfo.getPrintTime().getTime() - tempApiRequestTimeDetail.getRequestTime());
						apiRequestTimeDetailList.add(tempApiRequestTimeDetail);
						tempApiRequestTimeDetail = new RequestTimeDetail();
					}
				}
			}
		}
		return apiRequestTimeDetailList;
	}
	
	
	
	public static void main(String[] args) {
//		parseDubboLog("interface = interface com.lvmama.comm.tnt.service.TntSellPackageService, method = getSellPackageListByChannel -- start");
		parseLog("2016-07-16 02:31:49,502 ERROR[LvLogS]client-service [FLUME-f4130278-6931-41b3-8638-e5bd70f9ce94] (ApiMethodIntercept.java:173) - ");
	}
}
